/*
 * Copyright 2012-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot;

import java.lang.reflect.Constructor;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.boot.Banner.Mode;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CommandLinePropertySource;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
 * 这个类可以用来从 Java 主方法启动并引导一个 Spring 应用程序。默认情况下，
 * 它会执行以下步骤来引导应用程序：
 *
 * <ul>
 * <li>创建一个合适的 {@link ApplicationContext} 实例（根据你的类路径决定）</li>
 * <li>注册一个 {@link CommandLinePropertySource}，将命令行参数作为 Spring 属性暴露出来</li>
 * <li>刷新应用上下文，加载所有单例 Bean</li>
 * <li>触发所有实现了 {@link CommandLineRunner} 的 Bean</li>
 * </ul>
 *
 * 在大多数情况下，你可以直接在 {@literal main} 方法中调用静态方法 {@link #run(Class, String[])} 来引导应用：
 *
 * <pre class="code">
 * &#064;Configuration
 * &#064;EnableAutoConfiguration
 * public class MyApplication  {
 *
 *   // ... Bean 定义
 *
 *   public static void main(String[] args) {
 *     SpringApplication.run(MyApplication.class, args);
 *   }
 * }
 * </pre>
 *
 * <p>
 * 对于更高级的配置，可以先创建并定制一个 {@link SpringApplication} 实例，然后再运行它：
 *
 * <pre class="code">
 * public static void main(String[] args) {
 *   SpringApplication application = new SpringApplication(MyApplication.class);
 *   // ... 在这里定制应用设置
 *   application.run(args);
 * }
 * </pre>
 *
 * {@link SpringApplication} 可以从多种不同来源读取 Bean。通常建议使用单个 {@code @Configuration} 类来引导应用，
 * 但你也可以通过 {@link #getSources()} 设置以下来源：
 * <ul>
 * <li>通过 {@link AnnotatedBeanDefinitionReader} 加载的完全限定类名</li>
 * <li>通过 {@link XmlBeanDefinitionReader} 加载的 XML 资源位置，或通过 {@link GroovyBeanDefinitionReader} 加载的 Groovy 脚本</li>
 * <li>通过 {@link ClassPathBeanDefinitionScanner} 扫描的包名</li>
 * </ul>
 *
 * 配置属性也会绑定到 {@link SpringApplication}，这使得可以动态设置 SpringApplication 的属性，
 * 例如添加额外的资源（"spring.main.sources"，CSV 列表），指定 Web 环境标志（"spring.main.web-application-type=none"），
 * 或关闭横幅（"spring.main.banner-mode=off"）等。
 *
 * @author Phillip Webb
 * @author Dave Syer
 * @author Andy Wilkinson
 * @author Christian Dupuis
 * @author Stephane Nicoll
 * @author Jeremy Rickard
 * @author Craig Burke
 * @author Michael Simons
 * @author Madhura Bhave
 * @author Brian Clozel
 * @author Ethan Rubinson
 * @author Chris Bono
 * @since 1.0.0
 * @see #run(Class, String[])
 * @see #run(Class[], String[])
 * @see #SpringApplication(Class...)
 */
public class SpringApplication {

	/**
	 * 默认的横幅（banner）位置。
	 */
	public static final String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;

	/**
	 * 横幅位置的属性键。
	 */
	public static final String BANNER_LOCATION_PROPERTY = SpringApplicationBannerPrinter.BANNER_LOCATION_PROPERTY;

	private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

	private static final Log logger = LogFactory.getLog(SpringApplication.class);

	static final SpringApplicationShutdownHook shutdownHook = new SpringApplicationShutdownHook();

	private Set<Class<?>> primarySources;

	private Set<String> sources = new LinkedHashSet<>();

	private Class<?> mainApplicationClass;

	private Banner.Mode bannerMode = Banner.Mode.CONSOLE;

	private boolean logStartupInfo = true;

	private boolean addCommandLineProperties = true;

	private boolean addConversionService = true;

	private Banner banner;

	private ResourceLoader resourceLoader;

	private BeanNameGenerator beanNameGenerator;

	private ConfigurableEnvironment environment;

	private WebApplicationType webApplicationType;

	private boolean headless = true;

	private boolean registerShutdownHook = true;

	private List<ApplicationContextInitializer<?>> initializers;

	private List<ApplicationListener<?>> listeners;

	private Map<String, Object> defaultProperties;

	private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;

	private Set<String> additionalProfiles = Collections.emptySet();

	private boolean allowBeanDefinitionOverriding;

	private boolean allowCircularReferences;

	private boolean isCustomEnvironment = false;

	private boolean lazyInitialization = false;

	private String environmentPrefix;

	private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;

	private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT;

	/**
	 * 创建一个新的 {@link SpringApplication} 实例。应用上下文将从指定的主要源中加载 Bean
	 *（详细信息参见 {@link SpringApplication 类级别} 的文档）。在调用 {@link #run(String...)} 之前，
	 * 可以自定义该实例。
	 * @param primarySources 主要的 Bean 源
	 * @see #run(Class, String[])
	 * @see #SpringApplication(ResourceLoader, Class...)
	 * @see #setSources(Set)
	 */
	public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	/**
	 * 创建一个新的 {@link SpringApplication} 实例。应用上下文将从指定的主要源加载 Bean
	 * （详见 {@link SpringApplication 类级别} 的文档说明）。
	 * 在调用 {@link #run(String...)} 之前，该实例可以进行自定义。
	 *
	 * @param resourceLoader 要使用的资源加载器
	 * @param primarySources 主要的 Bean 源
	 * @see #run(Class, String[])
	 * @see #setSources(Set)
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		// 根据类路径加载的类推断Web应用类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
		// 从 spring.factories 获取Bootstap注册初始化程序
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
		// 从 spring.factories 获取应用上下文初始化程序
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		// 从 spring.factories 获取应用监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		// 推断主应用程序main方法
		this.mainApplicationClass = deduceMainApplicationClass();
	}

	private Class<?> deduceMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		}
		catch (ClassNotFoundException ex) {
			// 吞下并继续
		}
		return null;
	}

	/**
	 * 运行 Spring 应用程序，创建并刷新一个新的 {@link ApplicationContext}。
	 * @param args 应用程序参数（通常由 Java main 方法传入）
	 * @return 一个正在运行的 {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		long startTime = System.nanoTime();
		//创建引导程序上下文
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
		//  配置Headless属性
		configureHeadlessProperty();
		// 配置启动监听器SpringApplicationRunListener
		SpringApplicationRunListeners listeners = getRunListeners(args);
		// 启动监听器【开始启动】
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 预处理环境信息prepareEnvironment
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			// 配置忽略Bean信息
			configureIgnoreBeanInfo(environment);
			// 打印横幅
			Banner printedBanner = printBanner(environment);
			// 创建应用上下文
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			// 准备上下文，Bean容器预处理
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			// 刷新上下文
			refreshContext(context);
			// Bean容器后处理
			afterRefresh(context, applicationArguments);
			// 计算启动完成时间
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
			listeners.started(context, timeTakenToStartup);
			// 调用运行程序
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
			listeners.ready(context, timeTakenToReady);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

	private DefaultBootstrapContext createBootstrapContext() {
		DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
		this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
		return bootstrapContext;
	}

	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
		// 创建和配置环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
		listeners.environmentPrepared(bootstrapContext, environment);
		DefaultPropertiesPropertySource.moveToEnd(environment);
		Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
				"Environment prefix cannot be set via properties.");
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
			environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

	private Class<? extends StandardEnvironment> deduceEnvironmentClass() {
		switch (this.webApplicationType) {
		case SERVLET:
			return ApplicationServletEnvironment.class;
		case REACTIVE:
			return ApplicationReactiveWebEnvironment.class;
		default:
			return ApplicationEnvironment.class;
		}
	}

	private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		// 设置环境
		context.setEnvironment(environment);
		// 后处理应用程序上下文
		postProcessApplicationContext(context);
		// 应用初始化程序
		applyInitializers(context);
		// 准备监听器上下文
		listeners.contextPrepared(context);
		// 关闭引导程序上下文
		bootstrapContext.close(context);
		if (this.logStartupInfo) {
			// 记录启动信息
			logStartupInfo(context.getParent() == null);
			// 记录启动配置文件信息
			logStartupProfileInfo(context);
		}
		// 添加特定于启动的单例bean
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			// 如果打印横幅存在，则将其注册为单例
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
			// 设置是否允许循环依赖
			((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
			if (beanFactory instanceof DefaultListableBeanFactory) {
				// 设置是否允许Bean相互覆盖
				((DefaultListableBeanFactory) beanFactory)
						.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
			}
		}
		if (this.lazyInitialization) {
			// 如果启动了延迟初始化，则添加延迟初始化Bean工厂后置处理器
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
		// 加载资源
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		// 执行加载资源操作
		load(context, sources.toArray(new Object[0]));
		// 加载到上下文中
		listeners.contextLoaded(context);
	}

	private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			// 如果启用了注册关闭钩子函数，则将关闭钩子注册到上下文
			shutdownHook.registerApplicationContext(context);
		}
		refresh(context);
	}

	private void configureHeadlessProperty() {
		// Headless模式，默认为true
		System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
				System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
	}

	private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
				this.applicationStartup);
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
		return getSpringFactoriesInstances(type, new Class<?>[] {});
	}

	private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = getClassLoader();
		// 使用名称并确保唯一以防止重复
		Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}

	@SuppressWarnings("unchecked")
	private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
			ClassLoader classLoader, Object[] args, Set<String> names) {
		List<T> instances = new ArrayList<>(names.size());
		for (String name : names) {
			try {
				Class<?> instanceClass = ClassUtils.forName(name, classLoader);
				Assert.isAssignable(type, instanceClass);
				Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
				T instance = (T) BeanUtils.instantiateClass(constructor, args);
				instances.add(instance);
			}
			catch (Throwable ex) {
				throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
			}
		}
		return instances;
	}

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		switch (this.webApplicationType) {
		case SERVLET:
			return new ApplicationServletEnvironment();
		case REACTIVE:
			return new ApplicationReactiveWebEnvironment();
		default:
			return new ApplicationEnvironment();
		}
	}

	/**
	 * 模板方法，依次调用
	 * {@link #configurePropertySources(ConfigurableEnvironment, String[])} 和
	 * {@link #configureProfiles(ConfigurableEnvironment, String[])}。
	 * 可重写此方法以完全控制环境的自定义，
	 * 或分别重写上述两个方法以精细控制属性源或配置文件。
	 * @param environment 当前应用的环境对象
	 * @param args 传递给 {@code run} 方法的参数
	 * @see #configureProfiles(ConfigurableEnvironment, String[])
	 * @see #configurePropertySources(ConfigurableEnvironment, String[])
	 */
	protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
		if (this.addConversionService) {
			environment.setConversionService(new ApplicationConversionService());
		}
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}

	/**
	 * 添加、移除或重新排序此应用环境中的任意 {@link PropertySource}。
	 * @param environment 当前应用的环境对象
	 * @param args 传递给 {@code run} 方法的参数
	 * @see #configureEnvironment(ConfigurableEnvironment, String[])
	 */
	protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
		if (!CollectionUtils.isEmpty(this.defaultProperties)) {
			DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
		}
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(
						new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}

	/**
	 * 配置此应用环境中哪些配置文件是激活的（或默认激活的）。
	 * 额外的配置文件可以通过配置文件处理中的 {@code spring.profiles.active} 属性激活。
	 * @param environment 当前应用的环境对象
	 * @param args 传递给 {@code run} 方法的参数
	 * @see #configureEnvironment(ConfigurableEnvironment, String[])
	 */
	protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
	}

	private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
		if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
			Boolean ignore = environment.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,
					Boolean.class, Boolean.TRUE);
			System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
		}
	}

	/**
	 * 绑定环境到 {@link SpringApplication}。
	 * @param environment 要绑定的环境
	 */
	protected void bindToSpringApplication(ConfigurableEnvironment environment) {
		try {
			Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
		}
		catch (Exception ex) {
			throw new IllegalStateException("Cannot bind to SpringApplication", ex);
		}
	}

	private Banner printBanner(ConfigurableEnvironment environment) {
		if (this.bannerMode == Banner.Mode.OFF) {
			return null;
		}
		ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
				: new DefaultResourceLoader(null);
		SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
		if (this.bannerMode == Mode.LOG) {
			return bannerPrinter.print(environment, this.mainApplicationClass, logger);
		}
		return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
	}

	/**
	 * 用于创建 {@link ApplicationContext} 的策略方法。默认情况下，该方法会优先使用显式设置的
	 * 应用上下文类或工厂，如果没有设置，则退回到合适的默认值。
	 * @return 应用上下文（尚未刷新）
	 * @see #setApplicationContextFactory(ApplicationContextFactory)
	 */
	protected ConfigurableApplicationContext createApplicationContext() {
		return this.applicationContextFactory.create(this.webApplicationType);
	}

	/**
	 * 对 {@link ApplicationContext} 进行相关的后处理。子类可根据需要添加额外处理。
	 * @param context 应用上下文
	 */
	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			// 如果配置了bean名称生成器，则将其注册为单例
			context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				// 如果上下文是通用应用上下文，为其设置资源加载器
				((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				// 如果上下文是默认资源加载器实例，设置类加载器
				((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
		if (this.addConversionService) {
			// 如果启用了转换服务，设置其为应用上下文的转换服务
			context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
		}
	}

	/**
	 * 在上下文刷新之前，应用所有的 {@link ApplicationContextInitializer}。
	 * @param context 配置好的 ApplicationContext（尚未刷新）
	 * @see ConfigurableApplicationContext#refresh()
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
			// 解析初始化器所需的类型
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
					ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
			// 进行初始化操作
			initializer.initialize(context);
		}
	}

	/**
	 * 用于记录启动信息，子类可以重写此方法以添加额外的日志。
	 * @param isRoot 如果此应用是上下文层次结构的根，则为 true
	 */
	protected void logStartupInfo(boolean isRoot) {
		if (isRoot) {
			new StartupInfoLogger(this.mainApplicationClass).logStarting(getApplicationLog());
		}
	}

	/**
	 * 用于记录激活的 profile 信息。
	 * @param context 应用上下文
	 */
	protected void logStartupProfileInfo(ConfigurableApplicationContext context) {
		Log log = getApplicationLog();
		if (log.isInfoEnabled()) {
			List<String> activeProfiles = quoteProfiles(context.getEnvironment().getActiveProfiles());
			if (ObjectUtils.isEmpty(activeProfiles)) {
				List<String> defaultProfiles = quoteProfiles(context.getEnvironment().getDefaultProfiles());
				String message = String.format("%s default %s: ", defaultProfiles.size(),
						(defaultProfiles.size() <= 1) ? "profile" : "profiles");
				log.info("No active profile set, falling back to " + message
						+ StringUtils.collectionToDelimitedString(defaultProfiles, ", "));
			}
			else {
				String message = (activeProfiles.size() == 1) ? "1 profile is active: "
						: activeProfiles.size() + " profiles are active: ";
				log.info("The following " + message + StringUtils.collectionToDelimitedString(activeProfiles, ", "));
			}
		}
	}

	private List<String> quoteProfiles(String[] profiles) {
		return Arrays.stream(profiles).map((profile) -> "\"" + profile + "\"").collect(Collectors.toList());
	}

	/**
	 * 返回应用的 {@link Log}。默认情况下会自动推断。
	 * @return 应用日志
	 */
	protected Log getApplicationLog() {
		if (this.mainApplicationClass == null) {
			return logger;
		}
		return LogFactory.getLog(this.mainApplicationClass);
	}

	/**
	 * 将 bean 加载到应用上下文中。
	 * @param context 需要加载 bean 的上下文
	 * @param sources 需要加载的资源
	 */
	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		// 创建bean定义加载器
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			// 设置bean名称生成器
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			// 设置资源加载器
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			// 设置环境
			loader.setEnvironment(this.environment);
		}
		// 加载bean
		loader.load();
	}

	/**
	 * 将在 ApplicationContext 中使用的 ResourceLoader。
	 * @return resourceLoader 在 ApplicationContext 中将使用的资源加载器（如果是默认则为 null）
	 */
	public ResourceLoader getResourceLoader() {
		return this.resourceLoader;
	}

	/**
	 * 用于 ApplicationContext 的 ClassLoader：
	 * 如果设置了 {@link #setResourceLoader(ResourceLoader)}，则使用该 ResourceLoader 的 ClassLoader，
	 * 否则如果上下文类加载器非空，则使用上下文类加载器，
	 * 否则使用 Spring 的 {@link ClassUtils} 类的加载器。
	 * @return ClassLoader（绝不为 null）
	 */
	public ClassLoader getClassLoader() {
		if (this.resourceLoader != null) {
			return this.resourceLoader.getClassLoader();
		}
		return ClassUtils.getDefaultClassLoader();
	}

	/**
	 * 获取 BeanDefinitionRegistry。
	 * @param context 应用上下文
	 * @return 如果能确定，则返回 BeanDefinitionRegistry
	 */
	private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
		if (context instanceof BeanDefinitionRegistry) {
			return (BeanDefinitionRegistry) context;
		}
		if (context instanceof AbstractApplicationContext) {
			return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory();
		}
		throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
	}

	/**
	 * 用于创建 {@link BeanDefinitionLoader} 的工厂方法。
	 * @param registry BeanDefinitionRegistry
	 * @param sources 要加载的资源
	 * @return 用于加载 Bean 的 {@link BeanDefinitionLoader}
	 */
	protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
		return new BeanDefinitionLoader(registry, sources);
	}

	/**
	 * 刷新底层的 {@link ApplicationContext}。
	 * @param applicationContext 要刷新的应用上下文
	 */
	protected void refresh(ConfigurableApplicationContext applicationContext) {
		applicationContext.refresh();
	}

	/**
	 * 上下文刷新后调用。
	 * @param context 应用上下文
	 * @param args 应用参数
	 */
	protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
	}

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}

	private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args);
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
		}
	}

	private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
		try {
			(runner).run(args.getSourceArgs());
		}
		catch (Exception ex) {
			throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
		}
	}

	private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
			SpringApplicationRunListeners listeners) {
		try {
			try {
				// 🚪处理异常对应的退出码逻辑，例如将异常类型映射为特定的退出码
				handleExitCode(context, exception);

				// 📣通知所有监听器应用启动失败
				if (listeners != null) {
					listeners.failed(context, exception);
				}
			}
			finally {
				// 📝报告失败的详细信息（通常会打印日志或输出错误报告）
				reportFailure(getExceptionReporters(context), exception);

				// 🧹如果应用上下文已经创建，执行关闭操作，释放资源
				if (context != null) {
					context.close();

					// ♻️注销失败的上下文，避免内存泄漏
					shutdownHook.deregisterFailedApplicationContext(context);
				}
			}
		}
		catch (Exception ex) {
			// ⚠️关闭上下文失败时，记录警告日志，但不影响主异常抛出
			logger.warn("Unable to close ApplicationContext", ex);
		}

		// 🚨将启动失败的原始异常重新抛出（包装为 RuntimeException）
		ReflectionUtils.rethrowRuntimeException(exception);
	}

	private Collection<SpringBootExceptionReporter> getExceptionReporters(ConfigurableApplicationContext context) {
		try {
			return getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class<?>[] { ConfigurableApplicationContext.class }, context);
		}
		catch (Throwable ex) {
			return Collections.emptyList();
		}
	}

	private void reportFailure(Collection<SpringBootExceptionReporter> exceptionReporters, Throwable failure) {
		try {
			for (SpringBootExceptionReporter reporter : exceptionReporters) {
				// 🔍尝试由异常报告器处理异常，如果处理成功则返回
				if (reporter.reportException(failure)) {
					// 🗂️注册已记录的异常，避免重复输出
					registerLoggedException(failure);
					return;
				}
			}
		}
		catch (Throwable ex) {
			// 继续对原始失败进行正常处理
		}
		// 🧾如果日志级别允许，记录错误日志并注册异常
		if (logger.isErrorEnabled()) {
			logger.error("Application run failed", failure);
			registerLoggedException(failure);
		}
	}

	/**
	 * 注册已记录的异常。默认情况下，如果是在主线程运行，此方法会抑制额外的堆栈跟踪打印。
	 * @param exception 已记录的异常
	 */
	protected void registerLoggedException(Throwable exception) {
		// 🛠️获取 Spring Boot 异常处理器（如果存在）
		SpringBootExceptionHandler handler = getSpringBootExceptionHandler();

		// ✅如果存在处理器，则将异常注册进去
		if (handler != null) {
			handler.registerLoggedException(exception);
		}
	}

	private void handleExitCode(ConfigurableApplicationContext context, Throwable exception) {
		int exitCode = getExitCodeFromException(context, exception);
		if (exitCode != 0) {
			if (context != null) {
				context.publishEvent(new ExitCodeEvent(context, exitCode));
			}
			SpringBootExceptionHandler handler = getSpringBootExceptionHandler();
			if (handler != null) {
				handler.registerExitCode(exitCode);
			}
		}
	}

	private int getExitCodeFromException(ConfigurableApplicationContext context, Throwable exception) {
		int exitCode = getExitCodeFromMappedException(context, exception);
		if (exitCode == 0) {
			exitCode = getExitCodeFromExitCodeGeneratorException(exception);
		}
		return exitCode;
	}

	private int getExitCodeFromMappedException(ConfigurableApplicationContext context, Throwable exception) {
		if (context == null || !context.isActive()) {
			return 0;
		}
		ExitCodeGenerators generators = new ExitCodeGenerators();
		Collection<ExitCodeExceptionMapper> beans = context.getBeansOfType(ExitCodeExceptionMapper.class).values();
		generators.addAll(exception, beans);
		return generators.getExitCode();
	}

	private int getExitCodeFromExitCodeGeneratorException(Throwable exception) {
		if (exception == null) {
			return 0;
		}
		if (exception instanceof ExitCodeGenerator) {
			return ((ExitCodeGenerator) exception).getExitCode();
		}
		return getExitCodeFromExitCodeGeneratorException(exception.getCause());
	}

	SpringBootExceptionHandler getSpringBootExceptionHandler() {
		if (isMainThread(Thread.currentThread())) {
			return SpringBootExceptionHandler.forCurrentThread();
		}
		return null;
	}

	private boolean isMainThread(Thread currentThread) {
		return ("main".equals(currentThread.getName()) || "restartedMain".equals(currentThread.getName()))
				&& "main".equals(currentThread.getThreadGroup().getName());
	}

	/**
	 * 返回已推断或显式配置的主应用程序类。
	 * @return 主应用程序类或 {@code null}
	 */
	public Class<?> getMainApplicationClass() {
		return this.mainApplicationClass;
	}

	/**
	 * 设置特定的主应用程序类，该类将用作日志来源并获取版本信息。默认情况下会推断主应用程序类。
	 * 如果没有显式的应用程序类，可以设置为 {@code null}。
	 * @param mainApplicationClass 要设置的主应用程序类或 {@code null}
	 */
	public void setMainApplicationClass(Class<?> mainApplicationClass) {
		this.mainApplicationClass = mainApplicationClass;
	}

	/**
	 * 返回正在运行的 Web 应用程序类型。
	 * @return Web 应用程序类型
	 * @since 2.0.0
	 */
	public WebApplicationType getWebApplicationType() {
		return this.webApplicationType;
	}

	/**
	 * 设置要运行的 Web 应用程序类型。如果未显式设置，将根据类路径推断 Web 应用程序类型。
	 * @param webApplicationType Web 应用程序类型
	 * @since 2.0.0
	 */
	public void setWebApplicationType(WebApplicationType webApplicationType) {
		Assert.notNull(webApplicationType, "WebApplicationType must not be null");
		this.webApplicationType = webApplicationType;
	}

	/**
	 * 设置是否允许通过注册与已有定义同名的定义来覆盖 Bean 定义。默认值为 {@code false}。
	 * @param allowBeanDefinitionOverriding 是否允许覆盖
	 * @since 2.1.0
	 * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean)
	 */
	public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
		this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
	}

	/**
	 * 设置是否允许 Bean 之间的循环依赖并自动尝试解决。默认值为 {@code false}。
	 * @param allowCircularReferences 是否允许循环依赖
	 * @since 2.6.0
	 * @see AbstractAutowireCapableBeanFactory#setAllowCircularReferences(boolean)
	 */
	public void setAllowCircularReferences(boolean allowCircularReferences) {
		this.allowCircularReferences = allowCircularReferences;
	}

	/**
	 * 设置是否应延迟初始化 Bean。默认值为 {@code false}。
	 * @param lazyInitialization 是否应延迟初始化
	 * @since 2.2
	 * @see BeanDefinition#setLazyInit(boolean)
	 */
	public void setLazyInitialization(boolean lazyInitialization) {
		this.lazyInitialization = lazyInitialization;
	}

	/**
	 * 设置应用程序是否为无头模式，不应实例化 AWT。默认值为 {@code true}，以防止显示 Java 图标。
	 * @param headless 是否为无头模式
	 */
	public void setHeadless(boolean headless) {
		this.headless = headless;
	}

	/**
	 * 设置创建的 {@link ApplicationContext} 是否应注册关闭钩子。默认值为 {@code true}，以确保 JVM 关闭时能够优雅处理。
	 * @param registerShutdownHook 是否应注册关闭钩子
	 * @see #getShutdownHandlers()
	 */
	public void setRegisterShutdownHook(boolean registerShutdownHook) {
		this.registerShutdownHook = registerShutdownHook;
	}

	/**
	 * 设置用于打印横幅的 {@link Banner} 实例，当没有提供静态横幅文件时使用。
	 * @param banner 要使用的 Banner 实例
	 */
	public void setBanner(Banner banner) {
		this.banner = banner;
	}

	/**
	 * 设置应用运行时显示横幅的模式。默认值为 {@code Banner.Mode.CONSOLE}。
	 * @param bannerMode 用于显示横幅的模式
	 */
	public void setBannerMode(Banner.Mode bannerMode) {
		this.bannerMode = bannerMode;
	}

	/**
	 * 设置应用启动时是否应记录应用信息。默认值为 {@code true}。
	 * @param logStartupInfo 是否记录启动信息
	 */
	public void setLogStartupInfo(boolean logStartupInfo) {
		this.logStartupInfo = logStartupInfo;
	}

	/**
	 * 设置是否应向应用上下文添加 {@link CommandLinePropertySource} 以暴露命令行参数。默认值为 {@code true}。
	 * @param addCommandLineProperties 是否应暴露命令行参数
	 */
	public void setAddCommandLineProperties(boolean addCommandLineProperties) {
		this.addCommandLineProperties = addCommandLineProperties;
	}

	/**
	 * 设置是否应将 {@link ApplicationConversionService} 添加到应用上下文的 {@link Environment} 中。
	 * @param addConversionService 是否添加应用转换服务
	 * @since 2.1.0
	 */
	public void setAddConversionService(boolean addConversionService) {
		this.addConversionService = addConversionService;
	}

	/**
	 * 添加可以用于初始化 {@link BootstrapRegistry} 的 {@link BootstrapRegistryInitializer} 实例。
	 * @param bootstrapRegistryInitializer 要添加的引导注册表初始化器
	 * @since 2.4.5
	 */
	public void addBootstrapRegistryInitializer(BootstrapRegistryInitializer bootstrapRegistryInitializer) {
		Assert.notNull(bootstrapRegistryInitializer, "BootstrapRegistryInitializer must not be null");
		this.bootstrapRegistryInitializers.addAll(Arrays.asList(bootstrapRegistryInitializer));
	}

	/**
	 * 设置默认环境属性，这些属性将会在现有 {@link Environment} 的基础上使用。
	 * @param defaultProperties 要设置的附加属性
	 */
	public void setDefaultProperties(Map<String, Object> defaultProperties) {
		this.defaultProperties = defaultProperties;
	}

	/**
	 * 方便的 {@link #setDefaultProperties(Map)} 替代方法。
	 * @param defaultProperties 一些 {@link Properties}
	 */
	public void setDefaultProperties(Properties defaultProperties) {
		this.defaultProperties = new HashMap<>();
		for (Object key : Collections.list(defaultProperties.propertyNames())) {
			this.defaultProperties.put((String) key, defaultProperties.get(key));
		}
	}

	/**
	 * 设置额外的 profile 值（在系统或命令行属性设置的基础上）。
	 * @param profiles 要设置的额外 profiles
	 */
	public void setAdditionalProfiles(String... profiles) {
		this.additionalProfiles = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(profiles)));
	}

	/**
	 * 返回一个不可变的正在使用的额外 profiles 集合。
	 * @return 额外的 profiles
	 */
	public Set<String> getAdditionalProfiles() {
		return this.additionalProfiles;
	}

	/**
	 * 设置在生成 bean 名称时应使用的 bean 名称生成器。
	 * @param beanNameGenerator bean 名称生成器
	 */
	public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
		this.beanNameGenerator = beanNameGenerator;
	}

	/**
	 * 设置应与创建的应用上下文一起使用的底层环境。
	 * @param environment 环境
	 */
	public void setEnvironment(ConfigurableEnvironment environment) {
		this.isCustomEnvironment = true;
		this.environment = environment;
	}

	/**
	 * 在调用 {@link #run(String...)} 时，将额外的类添加到用于构建 ApplicationContext 的主配置源中。
	 * <p>
	 * 此处添加的源会合并到构造函数中设置的源中。大多数用户应考虑使用
	 * {@link #getSources()}/{@link #setSources(Set)} 方法，而不是调用此方法。
	 *
	 * @param additionalPrimarySources 需要添加的额外主配置源类
	 * @see #SpringApplication(Class...)
	 * @see #getSources()
	 * @see #setSources(Set)
	 * @see #getAllSources()
	 */
	public void addPrimarySources(Collection<Class<?>> additionalPrimarySources) {
		this.primarySources.addAll(additionalPrimarySources);
	}

	/**
	 * 返回一个可修改的集合，包含在调用 {@link #run(String...)} 时将被添加到 ApplicationContext 中的配置源。
	 * <p>
	 * 此处设置的源会与构造函数中设置的主配置源一并使用。
	 *
	 * @return 应用程序的配置源集合
	 * @see #SpringApplication(Class...)
	 * @see #getAllSources()
	 */
	public Set<String> getSources() {
		return this.sources;
	}

	/**
	 * 设置用于创建 ApplicationContext 的额外配置源。每个配置源可以是：
	 * 类名、包名或 XML 资源的位置。
	 * <p>
	 * 此处设置的源会与构造函数中设置的主配置源一并使用。
	 *
	 * @param sources 需要设置的应用程序配置源
	 * @see #SpringApplication(Class...)
	 * @see #getAllSources()
	 */
	public void setSources(Set<String> sources) {
		Assert.notNull(sources, "Sources must not be null");
		this.sources = new LinkedHashSet<>(sources);
	}

	/**
	 * 返回一个不可变的集合，包含在调用 {@link #run(String...)} 时将被添加到 ApplicationContext 中的所有配置源。
	 * 该方法会合并构造函数中指定的主配置源和通过 {@link #setSources(Set) 显式设置} 的额外配置源。
	 *
	 * @return 所有配置源组成的不可变集合
	 */
	public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

	/**
	 * 设置加载资源时应使用的 {@link ResourceLoader}。
	 *
	 * @param resourceLoader 资源加载器
	 */
	public void setResourceLoader(ResourceLoader resourceLoader) {
		Assert.notNull(resourceLoader, "ResourceLoader must not be null");
		this.resourceLoader = resourceLoader;
	}

	/**
	 * 返回从系统环境获取配置属性时应使用的前缀。
	 *
	 * @return 环境配置属性前缀
	 * @since 2.5.0
	 */
	public String getEnvironmentPrefix() {
		return this.environmentPrefix;
	}

	/**
	 * 设置从系统环境获取配置属性时应使用的前缀。
	 *
	 * @param environmentPrefix 要设置的环境配置属性前缀
	 * @since 2.5.0
	 */
	public void setEnvironmentPrefix(String environmentPrefix) {
		this.environmentPrefix = environmentPrefix;
	}

	/**
	 * 设置用于创建应用程序上下文的工厂。如果未设置，默认使用一个根据应用类型自动选择上下文的工厂：
	 * - 对于 Servlet Web 应用，创建 {@link AnnotationConfigServletWebServerApplicationContext}
	 * - 对于 Reactive Web 应用，创建 {@link AnnotationConfigReactiveWebServerApplicationContext}
	 * - 对于非 Web 应用，创建 {@link AnnotationConfigApplicationContext}
	 *
	 * @param applicationContextFactory 上下文创建工厂
	 * @since 2.4.0
	 */
	public void setApplicationContextFactory(ApplicationContextFactory applicationContextFactory) {
		this.applicationContextFactory = (applicationContextFactory != null) ? applicationContextFactory
				: ApplicationContextFactory.DEFAULT;
	}

	/**
	 * 设置将应用于 Spring {@link ApplicationContext} 的 {@link ApplicationContextInitializer}。
	 * @param initializers 要设置的初始化器集合
	 */
	public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<>(initializers);
	}

	/**
	 * 添加要应用于 Spring {@link ApplicationContext} 的 {@link ApplicationContextInitializer} 初始化器。
	 *
	 * @param initializers 要添加的初始化器数组
	 */
	public void addInitializers(ApplicationContextInitializer<?>... initializers) {
		this.initializers.addAll(Arrays.asList(initializers));
	}

	/**
	 * 返回只读、有序的 Set，包含将应用于 Spring {@link ApplicationContext} 的所有初始化器。
	 *
	 * @return 初始化器的只读集合
	 */
	public Set<ApplicationContextInitializer<?>> getInitializers() {
		return asUnmodifiableOrderedSet(this.initializers);
	}

	/**
	 * 设置将应用于 SpringApplication 并注册到 {@link ApplicationContext} 的 {@link ApplicationListener}。
	 * @param listeners 要设置的监听器集合
	 */
	public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
		this.listeners = new ArrayList<>(listeners);
	}

	/**
	 * 添加要应用于 SpringApplication 并注册到 {@link ApplicationContext} 的 {@link ApplicationListener} 监听器。
	 *
	 * @param listeners 要添加的监听器数组
	 */
	public void addListeners(ApplicationListener<?>... listeners) {
		this.listeners.addAll(Arrays.asList(listeners));
	}

	/**
	 * 返回只读、有序的 Set，包含将应用于 SpringApplication 并注册到 {@link ApplicationContext} 的所有监听器。
	 *
	 * @return 监听器的只读集合
	 */
	public Set<ApplicationListener<?>> getListeners() {
		return asUnmodifiableOrderedSet(this.listeners);
	}

	/**
	 * 设置用于收集启动指标的 {@link ApplicationStartup}。
	 *
	 * @param applicationStartup 要使用的 ApplicationStartup 实例
	 * @since 2.4.0
	 */
	public void setApplicationStartup(ApplicationStartup applicationStartup) {
		this.applicationStartup = (applicationStartup != null) ? applicationStartup : ApplicationStartup.DEFAULT;
	}

	/**
	 * 返回用于收集启动指标的 {@link ApplicationStartup} 实例。
	 *
	 * @return 当前使用的 ApplicationStartup
	 * @since 2.4.0
	 */
	public ApplicationStartup getApplicationStartup() {
		return this.applicationStartup;
	}

	/**
	 * 返回一个 {@link SpringApplicationShutdownHandlers} 实例，用于添加或移除在 JVM 关闭前执行操作的处理器。
	 *
	 * @return 一个可用于管理关闭处理器的 SpringApplicationShutdownHandlers 实例
	 * @since 2.5.1
	 */
	public static SpringApplicationShutdownHandlers getShutdownHandlers() {
		return shutdownHook.getHandlers();
	}

	/**
	 * 可用于以默认配置运行指定源的 {@link SpringApplication} 的静态辅助方法。
	 *
	 * @param primarySource 要加载的主要源
	 * @param args          应用程序参数（通常从 Java 的 main 方法中传入）
	 * @return 运行中的 {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}

	/**
	 * 静态辅助方法，用于使用默认设置和用户提供的参数，从指定的源运行 {@link SpringApplication}。
	 * @param primarySources 要加载的主要源
	 * @param args 应用程序参数（通常由 Java main 方法传入）
	 * @return 正在运行的 {@link ApplicationContext}
	 */
	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

	/**
	 * 一个可用于启动应用程序的基本 main 方法。当通过命令行参数
	 * {@literal --spring.main.sources} 定义应用源时，此方法非常有用。
	 * <p>
	 * 大多数开发者应自定义 main 方法，并直接调用 {@link #run(Class, String...)} 方法。
	 *
	 * @param args 命令行参数
	 * @throws Exception 如果应用程序无法启动
	 * @see SpringApplication#run(Class[], String[])
	 * @see SpringApplication#run(Class, String...)
	 */
	public static void main(String[] args) throws Exception {
		SpringApplication.run(new Class<?>[0], args);
	}

	/**
	 * 静态辅助方法，用于退出一个 {@link SpringApplication} 并获取表示执行结果的退出码（成功返回 0，失败返回非零）。
	 * 该方法不会抛出异常，但会打印遇到的任何异常堆栈信息。
	 *
	 * 除了使用指定的 {@link ExitCodeGenerator} 外，还会使用容器中实现了
	 * {@link ExitCodeGenerator} 接口的 Spring Bean。
	 *
	 * 当存在多个生成器时，将使用第一个返回非零值的退出码。生成器的执行顺序依据其
	 * {@link Ordered} 接口实现或 {@link Order @Order} 注解定义的顺序。
	 *
	 * @param context 要关闭的应用上下文（如果可能）
	 * @param exitCodeGenerators 退出码生成器数组
	 * @return 执行结果的退出码（0 表示成功）
	 */
	public static int exit(ApplicationContext context, ExitCodeGenerator... exitCodeGenerators) {
		Assert.notNull(context, "Context must not be null");
		int exitCode = 0;
		try {
			try {
				ExitCodeGenerators generators = new ExitCodeGenerators();
				Collection<ExitCodeGenerator> beans = context.getBeansOfType(ExitCodeGenerator.class).values();
				generators.addAll(exitCodeGenerators);
				generators.addAll(beans);
				exitCode = generators.getExitCode();
				if (exitCode != 0) {
					context.publishEvent(new ExitCodeEvent(context, exitCode));
				}
			}
			finally {
				close(context);
			}
		}
		catch (Exception ex) {
			ex.printStackTrace();
			exitCode = (exitCode != 0) ? exitCode : 1;
		}
		return exitCode;
	}

	private static void close(ApplicationContext context) {
		if (context instanceof ConfigurableApplicationContext) {
			ConfigurableApplicationContext closable = (ConfigurableApplicationContext) context;
			closable.close();
		}
	}

	private static <E> Set<E> asUnmodifiableOrderedSet(Collection<E> elements) {
		List<E> list = new ArrayList<>(elements);
		list.sort(AnnotationAwareOrderComparator.INSTANCE);
		return new LinkedHashSet<>(list);
	}

	/**
	 * 一个 {@link BeanFactoryPostProcessor}，用于将我们的属性源排序到由
	 * {@link ConfigurationClassPostProcessor} 添加的任何 {@code @PropertySource}
	 * 项之下。
	 */
	private static class PropertySourceOrderingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {

		private final ConfigurableApplicationContext context;

		PropertySourceOrderingBeanFactoryPostProcessor(ConfigurableApplicationContext context) {
			this.context = context;
		}

		@Override
		public int getOrder() {
			return Ordered.HIGHEST_PRECEDENCE;
		}

		@Override
		public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
			DefaultPropertiesPropertySource.moveToEnd(this.context.getEnvironment());
		}

	}

}
